%{
#include<stdlib.h>
#include<stdarg.h>
#include<string.h>
#include<stdio.h>
#include"CQLParser.h"
void yyerror(char*s, ...);
void emit(char* s, ...);

ParseNode* parseTree;
%}

%union{
    struct _ParseNode* node;
    int intval;
    double floatval;
    char* strval;
    int subtok;
}

%token <strval> ID
%token <strval> STRING
%token <intval> INTNUM
%token <intval> BOOL
%token <floatval> FLOATNUM

%right ASSIGN
%left <subtok> OR
%left <subtok> XOR
%left <subtok> NOT
%left <subtok> COMPARISON


%token CREATE
%token MATCH
%token WHERE
%token RETURN
%token DELETE
%token REMOVE
%token SET
%token MERGE
%token <subtok> AND
/* %token NOT  
%token OR
%token XOR */
%token CONN
%token POINT
%token EOL
%type <node> stmt_list stmt ddl dml 
%type <node> node_stmt  node_label opt_node opt_node_property_list node_property property_value
%type <node> create_stmt opt_create_node_list edge_name create_edge_stmt
%type <node>  match_stmt match_edge_stmt opt_match_node_list
%type <node> node_or_property
%type <node> opt_return opt_set opt_where opt_delete opt_remove opt_remove_sub join

%start start
/* %start stmt_list */
%%

/* 用于多次输入，之后将废弃 */
start: stmt_list
| stmt_list start

stmt_list: stmt EOL { parseTree = getParseTree($1); }

stmt: ddl { $$ = $1; }
| dml { $$ = $1; }

ddl: create_stmt { $$ = $1; }

dml: match_stmt { $$ = $1; }

/**********************************NODE_STMT  */
node_stmt: '(' opt_node ')'  { 
    /* CREATE 没有节点名 */
    $$=new_non_terminal_node(NT_CREATE, 2, NULL, $2); 
    }
| '(' node_label opt_node ')' {  
    ParseNode* nodeNameLabel = new_non_terminal_node(NT_NODE, 2, NULL, $2);
    $$=new_non_terminal_node(NT_CREATE, 2, nodeNameLabel, $3); 
    }
| '(' ID opt_node ')' { 
    ParseNode* nodeName = new_string_terminal_node(NT_STRING, $2);
    ParseNode* nodeNameLabel = new_non_terminal_node(NT_NODE, 2, nodeName, NULL);
    $$=new_non_terminal_node(NT_CREATE, 2, nodeNameLabel, $3);
    }
| '(' ID node_label opt_node ')' {
    ParseNode* nodeName = new_string_terminal_node(NT_STRING, $2);
    ParseNode* nodeNameLabel = new_non_terminal_node(NT_NODE, 2, nodeName, $3);
    $$=new_non_terminal_node(NT_CREATE, 2, nodeNameLabel, $4); 
    }

node_label: ':' ID {
    /* 第一次会进行规约，加入第一个孩子 */
        ParseNode* node = new_string_terminal_node(NT_STRING, $2);
        $$ = new_non_terminal_node(NT_NODE, 1, node); 
    }
| node_label ':' ID {
    /* node_label 存在递归，增加一个孩子 */
        non_terminal_add_child($1, 1);
        ParseNode* node = new_string_terminal_node(NT_STRING, $3);
        int childNum = $1->num_child;
        $1->children[childNum] = node;
        $1->num_child++;
        $$ = $1;
    }

opt_node: { $$ = NULL; }
| '{' opt_node_property_list '}' {
    /*  opt_node 与 opt_node_property_list节点相同 */
    $$ = $2;
}

opt_node_property_list: { $$ = NULL; }
| node_property {
    /* 第一次会进行规约，加入第一个孩子 */
    $$ = new_non_terminal_node(NT_NODE, 1, $1);
}
| opt_node_property_list ',' node_property {
    /* opt_node_property_list 存在递归，增加一个孩子 */
    non_terminal_add_child($1, 1);
    int childNum = $1->num_child;
    $1->children[childNum] = $3;
    $1->num_child++;
    $$ = $1;
}

node_property: ID ':' property_value {
    ParseNode* node = new_string_terminal_node(NT_STRING, $1);
    $$ = new_non_terminal_node(NT_NODE, 2, node, $3); 
}

property_value: STRING { $$ = new_string_terminal_node(NT_STRING, $1); }
| INTNUM { $$ = new_int_terminal_node(NT_INT, $1);  }
| FLOATNUM { $$ = new_float_terminal_node(NT_FLOAT, $1);  }
| BOOL { $$ = new_int_terminal_node(NT_INT, $1); }

/*********************************** CREATE_STMT */
create_stmt: CREATE node_stmt opt_create_node_list opt_return {
    $$ = new_non_terminal_node(NT_CREATE, 3, $2, $3, $4);
}

opt_create_node_list: { $$ = NULL; }
| opt_create_node_list CONN create_edge_stmt POINT node_stmt {
    if($$ == NULL){
        $$ = new_non_terminal_node(NT_NODE, 2, $3, $5); 
    }
    else{
        /* opt_create_node_list 存在递归，增加2个孩子 */
        non_terminal_add_child($1, 2);
        int childNum = $1->num_child;
        $1->children[childNum] = $3;
        $1->children[childNum+1] = $5;
        $1->num_child += 2;
        $$ = $1;
    } 
}

create_edge_stmt: '[' edge_name ':' ID opt_node ']' {
    ParseNode* node = new_string_terminal_node(NT_STRING, $4);
    $$ = new_non_terminal_node(NT_NODE, 3, $2, node, $5);
}

edge_name: { $$ = NULL; }
| ID { $$ = new_string_terminal_node(NT_STRING, $1); }

/************************************ MATCH_STMT */
match_stmt: MATCH node_stmt opt_match_node_list  opt_where opt_set opt_delete opt_remove opt_return {
    $$ = new_non_terminal_node(NT_MATCH, 7, $2, $3, $4, $5, $6, $7, $8);
}

opt_match_node_list: { $$ = NULL; }
| opt_match_node_list CONN match_edge_stmt POINT node_stmt {
    if($$ == NULL){
        $$ = new_non_terminal_node(NT_NODE, 2, $3, $5); 
    }
    else{
        /* opt_match_node_list 存在递归，增加2个孩子 */
        non_terminal_add_child($1, 2);
        int childNum = $1->num_child;
        $1->children[childNum] = $3;
        $1->children[childNum+1] = $5;
        $1->num_child += 2;
        $$ = $1;
    } 
}

match_edge_stmt: '[' ']' { $$ = NULL; }
| '[' node_label opt_node ']' {
    ParseNode* nodeNameLabel = new_non_terminal_node(NT_NODE, 2, NULL, $2);
    $$=new_non_terminal_node(NT_EDGE, 2, nodeNameLabel, $3); 
}
| '[' ID opt_node ']' {
    ParseNode* nodeName = new_string_terminal_node(NT_STRING, $2);
    ParseNode* nodeNameLabel = new_non_terminal_node(NT_NODE, 2, nodeName, NULL);
    $$=new_non_terminal_node(NT_EDGE, 2, nodeNameLabel, $3);
}
| '[' ID node_label opt_node ']' {
    ParseNode* nodeName = new_string_terminal_node(NT_STRING, $2);
    ParseNode* nodeNameLabel = new_non_terminal_node(NT_NODE, 2, nodeName, $3);
    $$=new_non_terminal_node(NT_EDGE, 2, nodeNameLabel, $4); 
}

/************************************** SET_STMT */
opt_set: { $$ = NULL; }
| SET node_or_property COMPARISON property_value {
    ParseNode* node = new_int_terminal_node(NT_COMPARISON, $3);
    $$ = new_non_terminal_node(NT_SET, 3, $2, $3, $4);
}

/************************************ WHERE_STMT */
opt_where: { $$ = NULL; }
| WHERE node_or_property COMPARISON property_value {
    ParseNode* node = new_int_terminal_node(NT_COMPARISON, $3);
    $$ = new_non_terminal_node(NT_WHERE, 3, $2, $3, $4);
}
| opt_where join node_or_property COMPARISON property_value {
     /* opt_where 存在递归，增加4个孩子 */
     non_terminal_add_child($1, 4);
    ParseNode* node = new_int_terminal_node(NT_COMPARISON, $4);
    int childNum = $1->num_child;
    $1->children[childNum] = $2;
    $1->children[childNum+1] = $3;
    $1->children[childNum+2] = node;
    $1->children[childNum+3] = $5;
    $1->num_child += 4;
    $$ = $1;
}

join: AND { $$ = new_int_terminal_node(NT_AND, $1); }
| OR { $$ = new_int_terminal_node(NT_OR, $1); }
| XOR { $$ = new_int_terminal_node(NT_XOR, $1); }

node_or_property: ID {
    ParseNode* node = new_string_terminal_node(NT_STRING, $1);
    $$ = new_non_terminal_node(NT_NODE, 1, node);
    }
| ID '.' ID {
    ParseNode* nodeL = new_string_terminal_node(NT_STRING, $1);
    ParseNode* nodeR = new_string_terminal_node(NT_STRING, $3);
    $$ = new_non_terminal_node(NT_NODE, 2, nodeL, nodeR);
}

/*********************************** DELETE_STMT */
opt_delete: { $$ = NULL; }
| DELETE ID { 
    ParseNode* node = new_string_terminal_node(NT_STRING, $2); 
    $$ = new_non_terminal_node(NT_DELETE, 1, node);
    }
| opt_delete ',' ID {
    /* opt_delete 存在递归，增加一个孩子 */
    non_terminal_add_child($1, 1);
    ParseNode* node = new_string_terminal_node(NT_STRING, $3);
    int childNum =  $1->num_child;
    $1->children[childNum] = node;
    $1->num_child++;
    $$ = $1;
}

/************************************ REMOVE_STMT */
opt_remove: { $$=NULL; }
| REMOVE opt_remove_sub {
    $$ = new_non_terminal_node(NT_REMOVE, 1, $2);
    }
| opt_remove ',' opt_remove_sub {
    non_terminal_add_child($1, 1);
    int childNum = $1->num_child;
    $1->children[childNum] = $3;
    $1->num_child++;
    $$ = $1; 
    }

opt_remove_sub: ID node_label {
    ParseNode* node = new_string_terminal_node(NT_STRING, $1);
    $$ = new_non_terminal_node(NT_NODE, 2, node, $2);
    }
| ID '.' ID {
    ParseNode* nodeL = new_string_terminal_node(NT_STRING, $1);
    ParseNode* nodeR = new_string_terminal_node(NT_STRING, $3);
    $$ = new_non_terminal_node(NT_NODE, 2, nodeL, nodeR);
}

/*********************************** RETURNT_STMT */
opt_return: { $$=NULL; }
| RETURN node_or_property {
    $$ = new_non_terminal_node(NT_RETURN, 1, $2);
}
| opt_return ',' node_or_property {
    non_terminal_add_child($1, 1);
    int childNum = $1->num_child;
    $1->children[childNum] = $3;
    $1->num_child++;
    $$ = $1;
}
%%

void yyerror(char* s, ...){
    extern yylineno;
    
    va_list ap;
    va_start(ap, s);

    fprintf(stderr, "err:lineno:%d", yylineno);
    vfprintf(stderr, s, ap);
    fprintf(stderr, "\n");
}

void emit(char* s, ...){
    extern yylineno;

    va_list ap;
    va_start(ap, s);
    
    printf("rpn: ");
    vfprintf(stdout, s, ap);
    printf("\n");

}

int main(int argc, char** argv){
    if(!yyparse()){
        printf("CQL parse worked\n");
    }
    else{
        printf("CQL parse failed\n");
    }

    return 0;
}